package top.starshine.pack;

import cn.hutool.log.Log;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * <h1 color="#409EFF"> 系统 StringBuilder 对象池 </h1>
 *
 * @Since: 🫵👁️👁️👉 [ @git/develop ][ @date/2025-09-09 ][ @author/??? ]
 */
final class SystemStringBuilderPool implements Runnable {

    // 对象池配置
    private final int maxPoolSize;// 最大数量
    private final int stringBuilderInitSize;// StringBuilder 的 value 数组初始值
    private final int stringBuilderMaxSize;// StringBuilder 的 value 数组最大值
    private final long maxIdleTime;// 空闲时间（秒）

    // 对象池管理
    private final ConcurrentLinkedQueue<StringBuilder> pool;// 池
    private final ConcurrentHashMap<StringBuilder, Long> lastBorrowTimeMap;// 存储空闲时间
    private final ScheduledExecutorService cleanupExecutor;// 定时器

    public SystemStringBuilderPool (SystemStringBuilderPoolProperties properties) {
        this(
                properties.getMaxSize(),
                properties.getStringBuilderInitSize(),
                properties.getStringBuilderMaxSize(),
                properties.getMaxIdleTime()
        );
    }

    public SystemStringBuilderPool (
            int maxPoolSize,
            int stringBuilderInitSize,
            int stringBuilderMaxSize,
            long maxIdleTime
    ) {
        this.maxPoolSize = maxPoolSize;
        this.stringBuilderInitSize = stringBuilderInitSize;
        this.stringBuilderMaxSize = stringBuilderMaxSize;
        this.maxIdleTime = maxIdleTime;
        this.pool = new ConcurrentLinkedQueue<>();
        this.lastBorrowTimeMap = new ConcurrentHashMap<>();

        // 初始化清理线程
        this.cleanupExecutor = Executors.newSingleThreadScheduledExecutor(r -> {
            Thread thread = new Thread(
                    r,
                    SystemStringBuilderPool.class.getSimpleName() + "-Cleanup"
            );
            thread.setDaemon(true);// 守护进程
            return thread;
        });

        // 定期清理空闲过期的StringBuilder
        this.cleanupExecutor.scheduleAtFixedRate(
                this,
                maxIdleTime / 2, // 初始延迟 30s / 2 = 15s
                maxIdleTime / 2, // 执行间隔 30s / 2 = 15s
                TimeUnit.SECONDS // 时间单位表示一秒
        );
    }

    /**
     * <h2 color="#409EFF"> 从池中获取 StringBuilder </h2>
     *
     * @Since: 🫵👁️👁️👉 [ @git/develop ][ @date/2025-09-09 ][ @author/??? ]
     */
    public StringBuilder borrow () {
        StringBuilder sb = pool.poll();

        if (sb == null) {
            // 创建新对象
            if (1 > stringBuilderInitSize) {
                sb = new StringBuilder();
            } else {
                sb = new StringBuilder(stringBuilderInitSize);
            }
        } else {
            // 找到可重用的对象
            sb.setLength(0); // 清空内容
        }

        // 记录借用时间
        lastBorrowTimeMap.put(sb, System.currentTimeMillis());
        return sb;
    }

    /**
     * <h2 color="#409EFF"> 将 StringBuilder 返回到池中 </h2>
     *
     * @Since: 🫵👁️👁️👉 [ @git/develop ][ @date/2025-09-09 ][ @author/??? ]
     */
    public void retrieve (StringBuilder sb) {
        if (sb == null) {
            return;
        }

        // 如果池已满，则不回收
        if (pool.size() >= maxPoolSize) {
            lastBorrowTimeMap.remove(sb);
            return;
        }

        // 是不是借出对象
        if (lastBorrowTimeMap.containsKey(sb)) {
            if (sb.capacity() > stringBuilderMaxSize) {
                // 不回收过大的 StringBuilder
                if (LoggerTools.log.isDebugEnabled()) LoggerTools.log.debug(
                        "StringBuilder@{} size:{} 容量过大，不执行回收",
                        sb.hashCode(), sb.capacity()
                );
                lastBorrowTimeMap.remove(sb);// 移除该 StringBuilder
            } else {
                // 清空内容并放回池中
                sb.setLength(0);
                pool.offer(sb);
            }
        }

    }

    @Override
    public void run () {
        long currentTime = System.currentTimeMillis();

        // 遍历所有对象，回收空闲时间超过阈值的
        for (StringBuilder sb : lastBorrowTimeMap.keySet()) {
            Long lastBorrowTime = lastBorrowTimeMap.get(sb);
            if (lastBorrowTime != null && (currentTime - lastBorrowTime) > maxIdleTime) {
                if (lastBorrowTimeMap.remove(sb) != null) {
                    pool.remove(sb);
                }
            }
        }

    }

    /**
     * <h2 color="#409EFF"> 关闭对象池，释放资源 </h2>
     *
     * @Since: 🫵👁️👁️👉 [ @git/develop ][ @date/2025-09-09 ][ @author/??? ]
     */
    public void shutdown () {
        cleanupExecutor.shutdown();
        try {
            if (!cleanupExecutor.awaitTermination(5, TimeUnit.SECONDS)) {
                cleanupExecutor.shutdownNow();
            }
        } catch (InterruptedException e) {
            cleanupExecutor.shutdownNow();
            Thread.currentThread().interrupt();
        }
        pool.clear();
        lastBorrowTimeMap.clear();
    }

}
